"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const m_base_1 = tslib_1.__importDefault(require("../utils/m-base"));
const m_file_1 = tslib_1.__importDefault(require("../utils/m-file"));
const m_cmder_1 = tslib_1.__importDefault(require("../services/m-cmder"));
const m_writer_1 = tslib_1.__importDefault(require("../services/m-writer"));
/**flutter+dio文件书写器 */
class WriterFlutterDio extends m_writer_1.default {
    /**书写枚举 */
    async writeEnums() { }
    /**书写模型 */
    async writeModels() {
        const { data, dir } = this;
        for (const m of data.models) {
            const { name, description, props } = m;
            const uses = (m.uses || []).filter((x) => x.name != "map");
            const path = `${dir}/models/${m_base_1.default.camelToSnake(name)}.dart`;
            //定义文件框架
            const lines = [];
            //添加文件提示
            lines.push(...this.getFileTips());
            //添加模型引用
            const imports = [];
            imports.push(`// ignore_for_file: unused_import`);
            imports.push(`import 'dart:io';`);
            imports.push(`import 'package:intl/intl.dart';`);
            for (const u of uses.filter((x) => !x.isEnum)) {
                imports.push(`import "./${m_base_1.default.camelToSnake(u.file)}.dart";`);
            }
            lines.push(...imports);
            //添加一个空行
            lines.push("\t");
            //添加模型备注
            lines.push(...m_base_1.default.toDartNote(description));
            //添加模型定义开头
            lines.push(`class ${name} {`);
            //添加模型属性
            const body = [];
            for (const p of props)
                body.push(...this.getModelProp(p));
            lines.push(...m_base_1.default.ident(body, 2));
            //添加一个空行
            lines.push("\t");
            //添加模型构造器
            lines.push(...this.getModelConstructor(m));
            //添加一个空行
            lines.push("\t");
            //添加模型接收器
            lines.push(...this.getModelFromJson(m));
            //添加一个空行
            lines.push("\t");
            //添加模型序列器
            lines.push(...this.getModelToJson(m));
            //添加模型结尾
            lines.push("}");
            //添加一个空行
            lines.push("\t");
            //写入文件
            await m_file_1.default.writeFile(path, m_base_1.default.toRows(lines));
        }
    }
    /**书写请求函数 */
    async writeMethods() {
        const { data, dir } = this;
        for (const m of data.methods) {
            const group = m.group || "";
            const base = m.base || "";
            const uses = (m.uses || []).filter((x) => x.name != "map");
            const urls = m.urls || [];
            const funcs = m.funcs || [];
            const path = `${dir}/${m_base_1.default.camelToSnake(group)}.dart`;
            //定义文件框架
            const lines = [];
            //添加文件提示
            lines.push(...this.getFileTips());
            //添加模型引用
            const imports = [];
            imports.push(`// ignore_for_file: unused_import`);
            imports.push(`import 'dart:io';`);
            imports.push(`import 'package:intl/intl.dart';`);
            imports.push(`import 'package:dio/dio.dart';`);
            //TODO: 优化引用(指向项目根目录)
            imports.push(`import '../../dio_config.dart';`);
            for (const u of uses.filter((x) => !x.isEnum)) {
                imports.push(`import "./models/${m_base_1.default.camelToSnake(u.file)}.dart";`);
            }
            lines.push(...imports);
            //添加两个空行
            lines.push("\t\t");
            //添加请求项目名称
            const baseName = `const baseName = "${base}";`;
            lines.push(...[...m_base_1.default.toDartNote("定义请求项目名称"), baseName]);
            //添加两个空行
            lines.push("\t\t");
            //添加请求地址
            const paths = [];
            for (const u of urls) {
                const { name, description, value } = u;
                const desc = m_base_1.default.toDartNote(description);
                const dim = `const ${name} = "${value}";`;
                paths.push(...[...desc, dim]);
            }
            lines.push(...paths);
            //添加两个空行
            lines.push("\t\t");
            //添加请求函数
            const apis = [];
            for (const f of funcs) {
                apis.push(...this.getMethodFunc(f));
            }
            lines.push(...apis);
            //添加一个空行
            lines.push("\t");
            //写入文件
            await m_file_1.default.writeFile(path, m_base_1.default.toRows(lines));
        }
    }
    /**获取文件顶部提示内容 */
    getFileTips() {
        const cmd = m_cmder_1.default.encodeArgs(this.parm);
        return [
            ...m_base_1.default.toCommonNote("此文件代码由接口发布器swg生成，请勿手动修改。"),
            ...m_base_1.default.toCommonNote(`命令行中执行 '${cmd["cmd"]}' 将重新生成。`),
            "\t",
        ];
    }
    /**获取模型属性定义字符串 */
    getModelProp(prop) {
        const n = (prop.name || "").replace(/^_+/, "");
        const name = m_base_1.default.snakeToCamel(n, true);
        const description = prop.description || "";
        const note = m_base_1.default.toDartNote(description);
        const typeStr = this.getModelTypeStr(prop);
        const dim = `${typeStr} ${name};`;
        return [...note, dim];
    }
    /**获取模型构造函数定义字符串 */
    getModelConstructor(model) {
        const m = model || {};
        const props = m.props || [];
        const mName = m.name || "";
        const desc = m.description || "";
        const lines = [];
        const hasProps = props.length > 0;
        lines.push(...m_base_1.default.toDartNote(desc || `实例化${mName}`));
        lines.push(`${mName}(${hasProps ? "{" : ""}`);
        const body = [];
        for (const p of props) {
            const { required, nullable } = p;
            const n = (p.name || "").replace(/^_+/, "");
            const name = m_base_1.default.snakeToCamel(n, true);
            const typeStr = this.getModelTypeStr(p);
            const value = this.getModelValueStr(p);
            const must = required || !nullable;
            const need = /^list</i.test(typeStr) ? false : must;
            const val = value && value != "null" ? ` = ${value}` : "";
            body.push(`${need ? "required " : ""}this.${name}${val},`);
        }
        lines.push(...m_base_1.default.ident(body, 2));
        lines.push(`${hasProps ? "}" : ""});`);
        return m_base_1.default.ident(lines, 2);
    }
    /**获取模型接收器符串 */
    getModelFromJson(model) {
        const m = model || {};
        const props = m.props || [];
        const mName = m.name || "";
        const desc = m.description || "";
        const ignores = "File,Blob".split(",");
        const bases = "int,double,bool,String,dynamic".split(",");
        const lines = [];
        const hasProps = props.length > 0;
        lines.push(...m_base_1.default.toDartNote(desc || `反序列化化${mName}`));
        lines.push(`${mName}.fromJson(Map<String, dynamic> json)${hasProps ? ":" : ";"}`);
        const body = [];
        for (const p of props) {
            const n = (p.name || "").replace(/^_+/, "");
            const name = m_base_1.default.snakeToCamel(n, true);
            const type = this.getModelTypeStr(p).replace(/\?$/, "");
            const subType = (type.split("List<")[1] || "").split(">")[0];
            let val = "";
            if (bases.includes(type) || type.includes("Map<")) {
                val = `json['${name}']`;
            }
            else if (ignores.includes(type)) {
                val = "null";
            }
            else if (/^List</.test(type) && bases.includes(subType)) {
                val = `json['${name}'] ?? []`;
            }
            else if (/^List</.test(type)) {
                val = `((json['${name}'] ?? []) as List<dynamic>).map((m)=> ${subType}.fromJson(m)).toList()`;
            }
            else if (type == "DateTime") {
                val = `json['${name}'] != null? DateFormat("yyyy-MM-ddTHH:mm:ss").parse(json['${name}']): null`;
            }
            else {
                val = `json['${name}'] != null ? ${type}.fromJson(json['${name}']) : null`;
            }
            body.push(`${name} = ${val},`);
        }
        if (body.length > 0) {
            body[body.length - 1] = body[body.length - 1].replace(/\,$/, ";");
        }
        lines.push(...m_base_1.default.ident(body, 2));
        return m_base_1.default.ident(lines, 2);
    }
    /**获取模型序列器符串 */
    getModelToJson(model) {
        const m = model || {};
        const props = m.props || [];
        const mName = m.name || "";
        const desc = m.description || "";
        const ignores = "File,Blob".split(",");
        const bases = "int,double,bool,String,dynamic".split(",");
        const lines = [];
        lines.push(...m_base_1.default.toDartNote(desc || `序列化${mName}`));
        lines.push(`Map<String,dynamic> toJson() => {`);
        const body = [];
        for (const p of props) {
            const n = (p.name || "").replace(/^_+/, "");
            const name = m_base_1.default.snakeToCamel(n, true);
            const must = p.required || !p.nullable;
            const type = this.getModelTypeStr(p).replace(/\?$/, "");
            const subType = (type.split("List<")[1] || "").split(">")[0];
            let val = "";
            if (bases.includes(type) || type.includes("Map<")) {
                val = `${name}`;
            }
            else if (ignores.includes(type)) {
                val = `null`;
            }
            else if (/^List</.test(type) && bases.includes(subType)) {
                val = `${name}`;
            }
            else if (/^List</.test(type)) {
                val = `${name}.map((m)=> m.toJson()).toList()`;
            }
            else if (type == "DateTime") {
                val = `${name} != null? DateFormat("yyyy-MM-ddTHH:mm:ss").format(${name}!): null`;
            }
            else {
                val = `${name}${!must ? "?" : ""}.toJson()`;
            }
            body.push(`"${name}": ${val},`);
        }
        lines.push(...m_base_1.default.ident(body, 2));
        lines.push(`};`);
        return m_base_1.default.ident(lines, 2);
    }
    /**获取请求函数定义 */
    getMethodFunc(func) {
        const { name, method, urlName, description } = func || {};
        const { inputParms, inputModel, outputModel } = func || {};
        const bases = "int,double,bool,String,dynamic".split(",");
        const ignores = "File,Blob".split(",");
        const parm = this.getMethodParm(inputParms);
        const parms = parm.filter((x) => !x.inPath).map((x) => x.prop);
        const paths = parm.filter((x) => x.inPath).map((x) => x.prop);
        const input = this.getTypeStr(inputModel);
        const output = this.getTypeStr(outputModel) || "dynamic";
        //定义函数框架
        const lines = [];
        //添加函数注释
        lines.push(...m_base_1.default.toDartNote(description));
        //添加函数定义
        let mParm = "{";
        if (input)
            mParm = `${mParm}required ${input} body, `;
        parm.forEach((x) => (mParm = `${mParm}${x.dim}, `));
        mParm = `${mParm}Options? options, CancelToken? canceller`;
        if (method != "delete")
            mParm = `${mParm}, ProgressCallback? onProgress`;
        mParm = `${mParm}}`;
        const mRes = output ? `Future<${output}>` : `Future`;
        lines.push(`${mRes} ${name}(${mParm}) async {`);
        //添加函数任务
        const task = [];
        task.push(`String reqPath = ${urlName};`);
        task.push(`Options reqConf = options ?? Options();`);
        task.push(`Map<String,dynamic> reqHeaders = reqConf.headers ?? {};`);
        task.push(`reqHeaders["baseName"] = baseName;`);
        task.push(`reqConf.headers = reqHeaders;`);
        const parmList = [`options: reqConf,`, `cancelToken: canceller,`];
        if (input && input.includes("Map<")) {
            task.push(`body.forEach((k, v) => v is File ? body[k] = MultipartFile.fromFileSync(v.path) : body[k] = v);`);
            task.push(`final reqBody = FormData.fromMap(body);`);
            parmList.unshift(`data: reqBody,`);
        }
        else if (input) {
            parmList.unshift(`data: body,`);
        }
        //添加请求头处理
        //添加请求地址处理
        if (paths.length > 0) {
            task.push(`Map<String,dynamic> reqPaths = { ${paths.join(", ")} };`);
            task.push(`reqPaths.forEach((k, v) => reqPath = reqPath.replaceAll('{$k}', v?.toString() ?? ''));`);
        }
        if (parms.length > 0) {
            task.push(`Map<String,dynamic> resParms = { ${parms.join(", ")} };`);
            parmList.unshift(`Uri(path: reqPath, queryParameters: resParms),`);
        }
        else {
            parmList.unshift(`Uri(path: reqPath),`);
        }
        if (method != "delete")
            parmList.push(`onReceiveProgress: onProgress,`);
        //添加dio定义
        task.push(`final dioRes = await dio.${method}Uri(`);
        task.push(...m_base_1.default.ident(parmList, 2));
        task.push(");");
        //添加返回值处理
        if (bases.includes(output) || ignores.includes(output)) {
            task.push(`return dioRes.data;`);
        }
        else if (/^List</i.test(output)) {
            const sub = (output.split("List<")[1] || "").split(">")[0];
            if (bases.includes(sub)) {
                task.push(`return dioRes.data;`);
            }
            else {
                task.push(`return dioRes.data.map((m)=> ${sub}.fromJson(m)).toList();`);
            }
        }
        else if (output == "DateTime") {
            task.push(`return DateFormat("yyyy-MM-ddTHH:mm:ss").parse(dioRes.data);`);
        }
        else {
            task.push(`return ${output}.fromJson(dioRes.data);`);
        }
        //把任务定义添加到文件框架中
        lines.push(...m_base_1.default.ident(task, 2));
        //添加函数结尾
        lines.push("}");
        return lines;
    }
    /**获取请求函数参数 */
    getMethodParm(parm) {
        const dims = parm.map((x) => {
            const name = x.name || "";
            const sign = !x.inPath ? "?" : "";
            const type = this.getTypeStr(x.type);
            if (!name)
                return { name: "", inPath: false, prop: "", dim: "" };
            return {
                name,
                inPath: x.inPath,
                prop: `"${name}": ${name}`,
                dim: `${type}${sign} ${name}`,
            };
        });
        return dims.filter((x) => !!x.name);
    }
    /**获取类型字符串 */
    getModelTypeStr(prop) {
        const { type, required, nullable } = prop || {};
        const nulls = "File,DateTime,dynamic".split(",");
        const must = required || !nullable;
        const str = this.getTypeStr(type);
        if (/^List</.test(str))
            return str;
        if (nulls.includes(str))
            return `${str}?`;
        return must ? str : `${str}?`;
    }
    /**获取默认值字符串 */
    getModelValueStr(prop) {
        const { type, required, nullable } = prop || {};
        const first = (type || [])[0] || {};
        const fType = first.type;
        const singles = "long,short,int,integer,int32,int64".split(",");
        const doubles = "number,double,float,decimal".split(",");
        if (fType == "array")
            return "const []";
        if (required)
            return "";
        if (nullable)
            return "null";
        if (singles.includes(fType))
            return "0";
        if (doubles.includes(fType))
            return "0.0";
        if (fType === "string")
            return `""`;
        if (fType === "boolean")
            return "false";
        return ``;
    }
    /**获取类型字符串 */
    getTypeStr(type) {
        const singles = "long,short,integer,int32,int64,int".split(",");
        const doubles = "number,double,float,decimal".split(",");
        const objs = "object,blob".split(",");
        const types = (type || []).slice(0).reverse();
        //有多个类型的全部定义为any类型
        if (types.some((x) => x.type.includes(",")))
            return "dynamic";
        if (types.length > 0 && types[0].type == "map") {
            return "Map<String, dynamic>";
        }
        //类型链
        let str = "";
        for (const t of types) {
            const format = t.format || "";
            let tp = t.isEnum ? t.enumType || "string" : t.type;
            singles.forEach((x) => (tp = tp.replace(new RegExp(`^${x}$`), "int")));
            doubles.forEach((x) => (tp = tp.replace(new RegExp(`^${x}$`), "double")));
            objs.forEach((x) => (tp = tp.replace(new RegExp(`^${x}$`), "dynamic")));
            if (tp == "file")
                tp = "File";
            if (tp == "array")
                tp = "List";
            if (format.includes("date"))
                tp = "DateTime";
            tp = tp == "boolean" ? "bool" : tp;
            tp = tp == "string" ? "String" : tp;
            str = str ? `${tp}<${str}>` : tp;
        }
        return str;
    }
}
exports.default = WriterFlutterDio;
/**注册flutter+dio书写器 */
m_writer_1.default.register("flutter+dio", WriterFlutterDio);
